/******************************************************************************
 *
 * ngcap - network sniffer using raw sockets
 *
 * Author:        cr
 * E-mail:        cr.at.netgarage.org
 * WWW:           http://www.netgarage.org
 * Copyright (C): 2009 by cr
 *
 * This file is part of ngcap.
 *
 * ngcap is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ngcap is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ngcap.  If not, see <http://www.gnu.org/licenses/>.
 *
 *****************************************************************************/

#include "rawsocket.hpp"
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <cerrno>
#include <cstring>

using std::string;

RawSocket::RawSocket(int st, int p) :
                        socketType(st), protocol(p), state(UNDEFINED)
{
    if(geteuid()!=0){
        throw SocketError("you need to be root for using raw sockets");
    }
    sockfd = ::socket(PF_PACKET, socketType, htons(protocol));
    if (-1 == sockfd)
        throw SocketError(string("socket() failed: ") + strerror(errno));
    state=CREATED;
}


RawSocket::~RawSocket()
{
    if (state != CLOSED)
        close(sockfd);
}

ssize_t RawSocket::receive(void* data, int d) 
{
    domain=d;
    memset(&addr,0,sizeof(addr));
    addr.sll_family=domain;
    addr.sll_protocol=htons(protocol);
    ssize_t res;
    socklen_t length=sizeof(sockaddr);
    char buffer[MTU];
    res=recvfrom(sockfd, buffer, MTU, 0, (struct sockaddr*)&addr, &length);
    if (-1==res)
        throw SocketError(string("recvfrom() failed: ") + strerror(errno));
    memcpy(data, buffer, res);
    return res;
}


void RawSocket::setInterface(const std::string& intf)
{
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, intf.c_str(), intf.size());
    if (ioctl(sockfd, SIOCGIFADDR, (char*)&ifr)<0) {
        throw SocketError("ioctl() error");
    }
}
